<?php

/*
	formDefintion 	: array of names to define the formData
	formData 		: data that is ready to build the form with in the render method
	layout			: defines where to put the formData elements

*/

require_once "gui/spGuiMappingText.php";
require_once "html/extended/spRadioList.php";
require_once "html/spForm.php";
require_once "html/spBold.php";
require_once "html/spBreak.php";
require_once "html/spInput.php";
require_once "html/spSpan.php";

class spFormBuilder extends spDiv
{
	private $form;

	private $database;
	private $insertedFormElements 	= array();
	private $formData 				= array();		
	private $formDefintion			= array();
	private $buttonsTop 			= null;	
	private $buttonsBottom 			= null;	
	private $hiddenfields 			= array();
	private $layout					= null;				// based on spElement
	
	private $showSubTitles			= true;
	private $showRequired			= true;

	public function __construct( $database=null, $data=null )
	{
		/*
		parent::__construct( $data );
		parent::setClass( "formBuilder" );		
		*/
		parent::__construct();
		
		if ( isset($data["no_form"]) )
			$this->form = new spDiv( $data );
		else
			$this->form = new spForm( $data );
	
		parent::addChild( $this->form );
			
		$this->database = $database;
	
		$data["class"] 	= "formBuilder";
		$data["action"] = "www.marino.dk";
		$data["method"] = "post";
		
		$this->formDefintion = $this->createDefaultFormLayoutData();
		
		$this->setFormLayoutDefinition( $this->formDefintion );			// names
		$this->setFormLayout( $this->createDefaultLayout() );			// layout

		if ( isset($data["buttons"]) )
			$this->setFormButtons($data["buttons"]);
	}
	
	public function getForm()
	{
		return $form;
	}
	
	public function getLayout()
	{
		return $this->layout;
	}
	
	public function setDatabase( $database )
	{
		$this->database = $database;
	}
	
	public function createDefaultFormLayoutData()
	{
		return array(
			"<layout>default"
		);
	}		

	public function createDefaultLayout()
	{
		return new spDiv(array(
			"name_id" => "default"
		));
	}	
	
	public function showSubTitles( $show )
	{
		$this->showSubTitles = $show;
	}
	
	public function showRequired( $show )
	{
		$this->showRequired = $show;
	}

	public function addHiddenField( $name, $value )
	{
		$this->hiddenfields[] = array(
			"name" => $name,
			"value" => $value
		);
	}
	
	public function setFormLayout( $layout )
	{
		if ( !$this->layout==null )
		{
			//parent::removeChild( $this->layout );
			$this->form->removeChild( $this->layout );
		}
	
		$this->layout = $layout;
		//parent::addChild( $layout );
		$this->form->addChild( $layout );
	}
	
	public function setFormLayoutDefinition( $formDefinition )
	{
		$this->formDefinition = $formDefinition;
	}

	public function getFormLayoutData()
	{
		return $this->formData;
	}
	
	public function setFormButtonsTop( $buttons )
	{
		$this->buttonsTop = $buttons;
	}

	public function setFormButtonsBottom( $buttons )
	{
		$this->buttonsBottom = $buttons;
	}
	
	public function insertFormElement( $element )
	{
		$this->insertedFormElements[] = $element;
	}
		
	public function preProcess( $formDataIn )
	{
		$formData = array();
		
		foreach ( $formDataIn as $p )
		{
			if ( strlen($p)>7 && substr_compare($p, "<title>", 0, 7)==0 )
			{
				$formData[] = array(
					"type" => "<title>",
					"text" => substr( $p, 7 )
				);
				continue;
			}
		
			if ( strlen($p)>8 && substr_compare($p, "<layout>", 0, 8)==0 )
			{
				$formData[] = array(
					"type" => "<layout>",
					"text" => substr( $p, 8 )
				);
				continue;
			}		
		
			if ( $p=="<nextcolumn>" )
			{
				$formData[] = array(
					"type" => "<nextcolumn>"
				);
				continue;
			}

			if ( $p=="<nextrow>" )
			{
				$formData[] = array(
					"type" => "<nextrow>"
				);
				continue;
			}
			
			// check for elements that need to be hidden
			if ( $p[0]=="*" )
			{
				$partname = $p;
				$partname = ltrim( $partname, "*" );
				$parts = $this->database->findFormPart( $partname );
			
				foreach ( $parts as $part )
				{
					$formData[] = array(array(
						"type" => "hidden",
						"value" => $part["value"],
						"sql_col" => $part["sql_col"]
					));
				}
				continue;
			}
			
			$part = $this->database->findFormPart( $p );
			if ( $part==false )
			{
				echo "ERROR: formpart does not exists: ".$p."<br/>";
				continue;
			}
		
			$formData[] = $part;
		}
		
		return $formData;
	}
	
	public function createCustomElement( $comp )
	{
	}
	
	public function render( $indent=0 )
	{
		$this->formData = $this->preProcess( $this->formDefinition  );
		
		//$data = parent::getData();
		$data = $this->form->getData();
		
		$hidden = array();
		$insertHere = null;

		if ( $this->buttonsTop )
		{
			//$this->addChild( $this->buttonsTop );
			$this->form->addChild( $this->buttonsTop );
		}
	
		// create our form before rendering is done
		foreach ( $this->formData as $key => $comps )
		{
			$type = isset($comps["type"])?$comps["type"]:"";

			if ( $type=="<layout>" )
			{
				$insertHere = $this->layout->find( $comps["text"] );
				if ( $insertHere==false )
				{
					echo "ERROR: spFormBuilder -> could not find layout: ".$comps["text"]."<br/>";
					
					var_dump( $this->formDefinition );
					return;
				}
				
				continue;
			}
			
			if ( $type=="<title>" )
			{
				$insertHere->addChild(new spHeading(array(
					"content" => $comps["text"]
				)));
				continue;
			}
			
			// validate we have a valide insert_here
			if ( $insertHere==null )
			{
				echo "ERROR: spFormBuilder -> invalid layout data<br/>";
				return;
			}
			
			$groupContainer = null;
			if ( count($comps) )
			{
				// the formBuilderGroupContainter is used to show where errors are in the form
				$groupContainer = new spDiv(array(
					"class" => "formbuilderGroupContainer"
				));
				
				$insertHere->addChild( $groupContainer );
			}
			
			foreach ( $comps as $comp )
			{
				$border 	= isset($comp["border"])?$comp["border"]:"";
				$title 		= isset($comp["title"])?$comp["title"]:"";
				$subtitle	= isset($comp["subtitle"])?$comp["subtitle"]:"";
				$type		= isset($comp["type"])?$comp["type"]:"";
				$required	= isset($comp["required"])?$comp["required"]:"";
				$dvalue		= isset($comp["dvalue"])?$comp["dvalue"]:"";
				$list		= isset($comp["list"])?$comp["list"]:array();
				$list_csv	= isset($comp["list_csv"])?$comp["list_csv"]:"";
				$sql_col	= isset($comp["sql_col"])?$comp["sql_col"]:"";
				$value		= isset($comp["value"])?$comp["value"]:"";
				$name		= isset($comp["name"])?$comp["name"]:"";				
				$text		= isset($comp["text"])?$comp["text"]:"";
				$class		= isset($comp["class"])?$comp["class"]:"";
				$readonly 	= isset($comp["readonly"])?$comp["readonly"]:false;
				$displaypart= isset($comp["displaypart"])?$comp["displaypart"]:true;
				$valid		= isset($comp["valid"])?$comp["valid"]:true;
				
				$prefix = $this->database->getPrefix();
				
				if ( $border!="" )
					$groupContainer->addStyle( "border", $border );

				if ( $displaypart==false )
					$groupContainer->addStyle( "display", "none" );

					
				// container for form element
				$container = new spDiv(array(
					"class" => "form_".$sql_col
				));
				
				if ( !$valid )
				{
					$container->addClass( "form_error" );
					
					if ( isset($comp["error_msg"]) )
					{
						$container->addChild( new spParagraph(array(
							"content" => $comp["error_msg"]
						)));
					}
				}

				$groupContainer->addChild( $container );

				if ( $title!="" )
				{
					// title stuff
					$heading = new spBold(array(
						"content" => $title
					));
					if ( $required=="true" && $this->showRequired )
					{
						$heading->addChild( new spSpan(array(
							"class"		=> "formBuilderRequired",
							"content" 	=> "*"
						)));
					}
					$container->addChild( $heading );
					$container->addChild( new spBreak );
				}
				
				switch ( $type )
				{
					case "image":
						{
							$c = new spDiv(array(
								"class" => "spFormBuilderImage"
							));
							$imageUrl = new spInput(array(
								"class" => "spFormBuilderImageUrl",
								"type" 	=> "string",
								"name"	=> $prefix.$sql_col,
								"value" => $value
							));
							$imageBut = new spInput(array(
								"class" => "spFormBuilderImageButton",
								"type" 	=> "button",
								"value" => "..."
							));
							$c->addChild( $imageUrl );
							$c->addChild( $imageBut );
							$container->addChild( $c );
						}
						break;
				
					case "file":
						{
							$container->addChild(new spSpan(array(
								"content" => $value
							)));
							$e = new spInput(array(
								"type" => "file",
								"class" => $class,
								"name"	=> $prefix.$name,
								"value" => $value
							));

							$container->addChild( $e );
						}
						break;
				
					case "button":
						{
							$e = new spInput(array(
								"type" => "button",
								"class" => $class,
								"name"	=> $prefix.$name,
								"value" => $value
							));
							
							if ( $dvalue!="" )
								$e->addAttr( "data-dvalue", $dvalue );

							$container->addChild( $e );
						}
						break;
				
					case "custom":
						{
							$container->addChild( $this->createCustomElement( $comp ) );
						}
						break;
						
					// using jPicker: https://code.google.com/p/jpicker/downloads/detail?name=jpicker-1.1.6.zip&can=2&q=
					case "colorpicker":
						{
							$e = new spInput(array(
								"type" => "hidden",
								"class" => "spColorPicker",
								"name" => $prefix.$sql_col,
								"value" => $value
							));
	
							$container->addChild( $e );
						}
						break;

					case "element":
						{
							$container->addChild( $comp["element"] );
						}
						break;
						
					case "mappingtext":
						{
							$e = new spGuiMappingText(array(
								"list" => $list,
								"name" => $prefix.$sql_col
							));
							
							$container->addChild( $e );
						}
						break;
						
					case "radiolist":
						{
							$e = new spRadioList(array(
								"name" 	=> $prefix.$sql_col,
								"items" => $list
							));
							
							$e->setElementDataString( $value );
							$container->addChild( $e );
						}
						break;
						
					case "checkboxlist":
						{
							$e = new spCheckBoxList(array(
								"name" => $prefix.$sql_col
							));
							$e->addItems( $list );
							$e->setElementDataString( $value );
							
							$container->addChild( $e );
						}
						break;
				
					case "checkbox":
						{
							$label = new spLabel(array(
								"contentAfter" => $text
							));

							// note: we can not set the value because that is used for the actually checkbox state "on", "off"
							$input = new spInput(array(
								"class" => $class,
								"type" => "checkbox",
								"name" => $prefix.$sql_col
							));
							
							if ( $value=="on" )
								$input->addAttr( "checked", "checked" );
							
							$label->addChild( $input );
							
							$container->addChild( $label );
						}
						break;

					case "combobox":
						{
							$e = new spCombobox(array(
								"name" => $prefix.$sql_col
							));
							$e->addItems( $list );
							$e->addCSV( $list_csv );
							$e->setElementDataString( $value );
							$container->addChild( $e );
						}
						break;
				
					case "string":
						{
							$e = new spInput(array(
								"class" => $class,
								"type" => "text",
								"name" => $prefix.$sql_col,
								"value" => $value
							));
							
							if  ( $readonly )
								$e->setReadOnly( true );
							
							if ( $dvalue!="" )
								$e->addAttr( "data-dvalue", $dvalue );

							$container->addChild( $e );
						}
						break;
						
					case "password":
						{
							$e = new spInput(array(
								"class" => $class,
								"type" => "password",
								"name" => $prefix.$sql_col,
								"value" => $value
							));
							
							if  ( $readonly )
								$e->setReadOnly( true );
							
							if ( $dvalue!="" )
								$e->addAttr( "data-dvalue", $dvalue );

							$container->addChild( $e );
						}
						break;						
						
					case "date":
						{
							$e = new spInput(array(
								"class" => "spDate",
								"type" => "text",
								"name" => $prefix.$sql_col,
								"value" => $value
							));
							$container->addChild( $e );
						}
						break;
						
					case "textarea":
						{
							$e = new spTextArea(array(
								"name" => $prefix.$sql_col
							));
							
							$e->setReadOnly( $readonly );
							$e->setElementDataString( $value );

							if ( $dvalue!="" )
								$e->addAttr( "data-dvalue", $dvalue );

							$container->addChild( $e );
						}
						break;
						
					case "hidden":
						{	
							$e = new spInput(array(
								"class" => $class,
								"type" => "hidden",
								"name" => $prefix.$sql_col,
								"value" => $value
							));
							$hidden[] = $e;
						}
						break;
				}
				
				if ( !empty($subtitle) && $this->showSubTitles )
				{
					$container->addChild( new spBreak );
					$container->addChild(new spItalic(array(
						"class" => "formBuilderSubtitle",
						"content" => $subtitle
					)));
					$container->addChild( new spBreak );
				}		
			}
		}
	
		foreach ( $hidden as $h )
		{
			//$this->addChild( $h );
			$this->form->addChild( $h );
		}
		
		foreach ( $this->hiddenfields as $hidden )
		{
			$e = new spInput(array(
				"type" => "hidden",
				"name" => $hidden["name"],
				"value" => $hidden["value"]
			));
			//$this->addChild( $e );
			$this->form->addChild( $e );
		}
		
		foreach ( $this->insertedFormElements as $p )
		{
			//$this->addChild( $p );
			$this->form->addChild( $p );
		}
		
		if ( $this->buttonsBottom )
		{
			//$this->addChild( $this->buttonsBottom );
			$this->form->addChild( $this->buttonsBottom );
		}
		
		parent::render( $indent );
	}
}

?>